package com.xw.hchat.netty;

import com.alibaba.fastjson.JSON;
import com.xw.hchat.pojo.TbChatRecord;
import com.xw.hchat.service.ChatRecordService;
import com.xw.hchat.util.IdWorker;
import com.xw.hchat.util.SpringUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 处理消息的handler
 * TextWebSocketFrame: 在netty中，是用于为websocket专门处理文本的对象，frame是消息的载体
 */
public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    // 用来保存所有的客户端连接
    private static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd hh:MM");

    /**
     * 当Channel中有新的事件消息会自动调用
     * @Author liu zhiyong
     * @Date 2020/8/19 15:07
     * @param ctx
     * @param msg
     * @return void
     **/
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        // 当接收到数据后会自动调用

        // 获取客户端发送过来的文本消息
        String text = msg.text();
        System.out.println("接收到消息数据为：" + text);

        //消息转换成自定义的Message对象
        Message message = JSON.parseObject(text, Message.class);

        //通过SpringUtil工具类获取spring上下文容器
        ChatRecordService chatRecordService = SpringUtil.getBean(ChatRecordService.class);
        //通过SpringUtil工具类获取IdWorker ID生成器
        IdWorker idWorker = SpringUtil.getBean(IdWorker.class);

        switch (message.getType()){
            //处理客户端连接的消息
            case 0:
                //建立用户与通道的关联
                String userid = message.getChatRecord().getUserid();
                UserChannelMap.put(userid, ctx.channel());
                System.out.println("建立用户：" + userid + "与通道：" + ctx.channel().id() + "的关联");
                UserChannelMap.print();
                break;
            //处理客户端发送好友的消息
            case 1:
                System.out.println("接收到用户消息");
                //0.将聊天消息保存到数据库中
                TbChatRecord chatRecord = message.getChatRecord();
                chatRecordService.insert(chatRecord);

                //1.如果发送的好友在线，直接发送给好友
                //根据好友id，获取对应的通道
                String friendid = chatRecord.getFriendid();
                Channel channel1 = UserChannelMap.get(friendid);
                if(channel1 != null){
                    //从ChannelGroup查找对应的Channel是否存在
                    Channel channel2 = clients.find(channel1.id());
                    if(channel2 != null){
                        System.out.println(chatRecord.getUserid() + "发送消息给" + friendid + "：" + JSON.toJSONString(message));
                        channel2.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(message)));
                    }
                }
                else{
                    //2.如果不在线，暂时不发送
                    System.out.println("用户" + chatRecord.getFriendid() + "不在线");
                }

                break;
            case 999:
                System.out.println("TCP客户端测试数据：" + JSON.toJSONString(message));
                break;
        }

    }

    // 当有新的客户端连接服务器之后，会自动调用这个方法
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        // 将新的通道加入到clients
        clients.add(ctx.channel());
    }

    /**
     * 连接异常
     * @Author liu zhiyong
     * @Date 2020/8/19 15:22
     * @param ctx
     * @param cause
     * @return void
     **/
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("连接异常");
        UserChannelMap.removeByChannelId(ctx.channel().id().asLongText());
        ctx.channel().close();
    }

    /**
     * 用户断开连接
     * @Author liu zhiyong
     * @Date 2020/8/19 15:22
     * @param ctx
     * @return void
     **/
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        System.out.println("用户关闭通道连接");
        UserChannelMap.removeByChannelId(ctx.channel().id().asLongText());
        UserChannelMap.print();
    }
}
